#include "Interpretator.h"

int stringBelongVector(std::string str, std::vector<std::string> vect)
{
	int len = vect.size();

	for (int i = 0; i < len; i++) {
		if ( str == vect.at(i) ) return i;
	}
	return -1;
}

int findColumn(std::string str, std::vector< std::vector<std::string> > vect, int *type)
{
	int len = vect.size();
	int lastRow = vect.at(0).size() - 1;

	for (int i = 0; i < len; i++) {
		if ( str == vect.at(i).at(0) ) {
			if (vect.at(i).at(lastRow) == "INT") *type = CTINT;
			if (vect.at(i).at(lastRow) == "KEY") *type = CTKEY;
			if (vect.at(i).at(lastRow) == "VARCHAR") *type = CTVCHAR;
			return i;
		}
	}
	return -1;
}

int findPrimaryKey(std::vector< std::vector<std::string> > vect)
{
	int len = vect.size();

	for (int i = 0; i < len; i++) {
		if ( vect.at(i).back() == "KEY" )
			return i;
	}
	return -1;
}

std::vector<std::string> getLine(std::vector< std::vector<std::string> > vect, int line)
{
	int len = vect.size();
	std::vector<std::string> result;
	
	for (int i = 0; i < len; i++) {
		result.push_back( vect.at(i).at(line) );
	}

	return result;
}

std::vector< std::vector<std::string> > rotateTable(std::vector< std::vector<std::string> > vect)
{
	std::vector< std::vector<std::string> > result;
	int len = vect.at(0).size();
	
	for (int i = 0; i < len; i++) {
		result.push_back( getLine(vect, i) );
	}

	return result;
}

int calculatable(int type1, int type2)
{
	if ( (CTINT == type1 || CTKEY == type1) && (CTINT == type2 || CTKEY == type2) )
		return TRUE;
	else return FALSE;
}

int lineEqual(std::vector<std::string> line1, std::vector<std::string> line2)
{
	int len1 = line1.size();
	int len2 = line2.size();
	
	if (len1 != len2) return FALSE;

	for (int i = 0; i < len1; i++) {
		if (line1.at(i) != line2.at(i)) return FALSE;
	}
	return TRUE;
}

std::vector< std::vector<std::string> > vectorUnion(std::vector< std::vector<std::string> > first, std::vector< std::vector<std::string> > second)
{
	int lenFirst;
	int lenSecond;
	
	lenSecond = second.at(0).size();
	lenFirst = first.at(0).size();
	
	std::vector< std::vector<std::string> > result;
	for (int k = 0; k < lenSecond - 1; k++) {
		result.push_back(getLine(second, k));
	}

	for (int i = 1; i < lenFirst - 1; i++) {
		for (int j = 1; j < lenSecond - 1; j++) {
			if ( lineEqual(getLine(first, i), result.at(j)) ) break;
			if (j == lenSecond - 2) result.push_back(getLine(first, i));
		}
	}
	result.push_back(getLine(second, lenSecond - 1));
	return rotateTable(result);
}

std::vector<std::string> convertCharVectorToStringVector(std::vector<char *> vect)
{
	std::vector<std::string> resVect;
	int len = vect.size();

	for (int i = 0 ; i < len; i++) {
		if (vect.at(i) != NULL)
			resVect.push_back ( vect.at(i) );
	}

	return resVect;
}

std::vector< std::vector<std::string> > convertCharVectorToStringVector(std::vector< std::vector<char *> > vect)
{
	std::vector< std::vector<std::string> > result;
	int len = vect.size();

	for (int i = 0; i < len; i++)
		result.push_back(convertCharVectorToStringVector(vect.at(i)));
	return result;
}

std::string stringify(double x)
{
	std::ostringstream o;
	o << x;
	return o.str();
}

std::string stringify(int x)
{
	std::ostringstream o;
	o << x;
	return o.str();
}

double stringToDouble(std::string fromString)
{
	std::stringstream iss(fromString);
	double x;
	iss >> x;
	return x;
	
}

int isAlpha(char symb)
{
	if (('a' <= symb && symb <= 'z') || ('A' <= symb && symb <= 'Z'))
		return TRUE;
	return FALSE;
}

int isDigit(char symb)
{
	if (('0' <= symb && symb <= '9'))
		return TRUE;
	return FALSE;
}

cText::cText()
{
	currPos = -1;
}

void cText::savePos()
{
	prevPos = currPos + 1;
}

std::string cText::exceptionP(char * msg)
{
	std::string result;
	result += msg;
	result += " at position: ";
	result += stringify(this->prevPos);
	return result;
}

int cText::setMsg(char *sentence)
{
	this->msg.clear();
	this->msg += sentence;
	this->currPos = -1;
	return TRUE;
}

char cText::nextChar()
{
	int len = (int) strlen((char *) this->msg.data());
	if (this->currPos < len ) {
		this->currPos++;
		return (char) this->msg[this->currPos];
	}
	return FALSE;
}

int cText::ungetChar()
{
	if (this->currPos > 0) {
		this->currPos--;
		return TRUE;
	}
	else
		return FALSE;
}

int cToken::pushBack()
{
	this->isBufEmpty = FALSE;
	return TRUE;
}

int cToken::getBufType()
{
	return this->bufType;
}

std::string cToken::getBufStr()
{
	return this->bufStr;
}

double cToken::getBufValue()
{
	return this->bufValue;
}

int cToken::resWord(std::string buf)
{
	return FALSE;
}

std::string cToken::upReg(std::string data)
{
	std::string res(_strupr( (char *) data.data() ));
	return res;
}

int cToken::nextToken(cText *text)
{
	if (this->isBufEmpty == TRUE) {
		text->savePos();
		if (this->readToken(text) == TRUE) {
			return TRUE;
		}
		else {
			return FALSE;
		}
	}
	else {	// Buffer not empty
		this->isBufEmpty = TRUE;
		return TRUE;
	}
}

int cToken::readToken(cText *text)
{
	char symbol;
	double val = 0;
	this->bufStr.clear();

	for ( ; ; ) {
		symbol = text->nextChar();

		if (isDigit(symbol)) {	// Next symbol is a digit
			this->bufType = NUM;
			val = (symbol - '0');
			for (;;) {
				symbol = text->nextChar();
				if (symbol == FALSE)
					break;		
				if (!isDigit(symbol)) {

					if (symbol == '.') {	// Fractional part
						int count = 0;
						double fract = 0;
						for (;;) {
							symbol = text->nextChar();
							if (symbol == FALSE)
								break;
							if (!isdigit(symbol)) {
								// Unget symbol
								break;
							}
							count++;
							fract = fract * 10 + (symbol - '0');
						}
						for (int i = 0; i < count; i++) {
							fract = fract * 0.1;
						}
						val = val + fract;
					}	// if

					else {
						text->ungetChar();
					}

					break;
				}
				val = val * 10 + (symbol - '0');
			}
			this->bufValue = val;
			return TRUE;
		}

		else if (isAlpha(symbol)) {	// Next symbol is a letter or '_'
			this->bufType = ID;	
			this->bufStr += symbol;
			for (;;) {
				symbol = text->nextChar();
				if (symbol == FALSE)
					break;

				if (!isAlpha(symbol) && symbol != '_' && !isDigit(symbol)) {
					text->ungetChar();
					break;
				}
				else {
					this->bufStr += symbol;
				}

			}

			bufStr = this->upReg(this->bufStr);

			if ( this->resWord( this->bufStr ) == TRUE ) {
				this->bufType = RES;
			}

			return TRUE;
		}

		else if (symbol == '"') {
			symbol = text->nextChar();

			this->bufType = CNST;
			this->bufStr += symbol;

				for (;;) {
					symbol = text->nextChar();
					if (symbol == FALSE)
						break;

					if (symbol == '"') {
						break;
					}
					else {
						this->bufStr += symbol;
					}
				}
			return TRUE;
		}

		else if (symbol == '(') {	// Next symbol is an open bracket
			this->bufType = SYMB;
			this->bufStr += symbol;
			return TRUE;
		}

		else if (symbol == ')') {	// Next symbol is an close bracket
			this->bufType = SYMB;
			this->bufStr += symbol;
			return TRUE;
		}

		else if (symbol == '+' || symbol == '-' || symbol == '*' || symbol == '/') {	// Next symbol is an operator
			this->bufType = SYMB;
			this->bufStr += symbol;
			return TRUE;
		}

		else if (symbol == '<' || symbol == '>') {	// Next symbol is a comparison
			this->bufType = SYMB;
			this->bufStr += symbol;

			symbol = text->nextChar();
			if (symbol == '=' || (symbol == '>' && this->bufStr == "<"))
				this->bufStr += symbol;
			else
				text->ungetChar();
			return TRUE;
		}
		else if (symbol == '=') {	// Next symbol is a comparison
			this->bufType = SYMB;
			this->bufStr += symbol;
			return TRUE;
		}
		else if (symbol == '!') {	// Next symbol is a comparison
			this->bufType = SYMB;
			this->bufStr += symbol;

			symbol = text->nextChar();
			if (symbol == '=')
				this->bufStr += symbol;
			else {
				this->bufType = ERR;
				return FALSE;
			}
			return TRUE;
		}

		else if (symbol == ';') {	// Next symbol is an end of sentence
			this->bufType = SYMB;
			this->bufStr += symbol;
			return TRUE;
		}
		else if (symbol == ',') {	// Next symbol is a comma
			this->bufType = SYMB;
			this->bufStr += symbol;
			return TRUE;
		}
		else if (symbol == ' ') {
			continue;
		}
		else if (symbol == 13) {
			continue;
		}
		else if (symbol == 10) {
			continue;
		}
		else if (symbol == 0) {
			this->bufType = END;
			return FALSE;
		}
		else {
			this->bufType = ERR;
			return FALSE;
		}
	}
}


//															TREE

int cTree::readTree(cText *text, cToken *token)
{
	token->nextToken(text);

	if (token->getBufStr() == "SELECT") {
		this->select = new cSelect();
		this->select->readSelect(text, token);
	}
	else if (token->getBufStr() == "INSERT") {
		this->insert = new cInsert();
		this->insert->readInsert(text, token);
	}
	else if (token->getBufStr() == "DROP") {
		this->drop = new cDrop();
		this->drop->readDrop(text, token);
	}
	else if (token->getBufStr() == "CREATE") {
		this->create = new cCreate();
		this->create->readCreate(text, token);
	}
	else if (token->getBufStr() == "DELETE") {
		this->del = new cDelete();
		this->del->readDelete(text, token);
	}
	else if (token->getBufStr() == "UPDATE") {
		this->update = new cUpdate();
		this->update->readUpdate(text, token);
	}
	else if (token->getBufStr() == "HELPME") {
		this->help = new cHelp();
		this->help->readHelp(text, token);
	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instructions"));
		throw e;
	}

	return TRUE;
}

std::string cTree::execTree()
{
	if (this->select != NULL) {
		return this->select->execSelect();
	}
	else if (this->insert != NULL) {
		return this->insert->execInsert();
	}
	else if (this->drop != NULL) {
		return this->drop->execDrop();
	}
	else if (this->create != NULL) {
		return this->create->execCreate();
	}
	else if (this->del != NULL) {
		return this->del->execDelete();
	}
	else if (this->update != NULL) {
		return this->update->execUpdate();
	}
	else if (this->help != NULL) {
		return this->help->execHelp();
	}

	return FALSE;
}


//															SELECT

int cSelect::readTables(cText *text, cToken *token)
{
	for (;;) {
		token->nextToken(text);
		if (token->getBufType() == RES) {
			if (token->getBufStr() == "WHERE") {
				if (this->tables.empty() == TRUE) {
					dbmsException e;
					e.setMessage(text->exceptionP("Table name missed"));
					throw e;
				}
				token->pushBack();
				return TRUE;
			}
			else {
				this->tables.push_back(token->getBufStr());
			}
		}
/*		if (token->getBufType() == ID) {
			this->tables.push_back(token->getBufStr());
		}
*/
		if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name should be without quotation"));
			throw e;
		}

		token->nextToken(text);

		if (token->getBufType() == SYMB) {
			if (token->getBufStr() == ",") {
				continue;
			}
			else if (token->getBufStr() == ";") {
				return TRUE;
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Wrong symbol"));
				throw e;
			}
		}
		else if (token->getBufType() == RES && token->getBufStr() == "WHERE") {
			token->pushBack();
			return TRUE;
		}
		else if (token->getBufType() == END) {
			if (this->tables.empty() == TRUE) {
				dbmsException e;
				e.setMessage(text->exceptionP("Table name missed"));
				throw e;
				return FALSE;
			}
			return TRUE;
		}
		else if (token->getBufType() == ERR) {
			dbmsException e;
			e.setMessage(text->exceptionP("Unexpected symbol(s)"));
			throw e;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Comma missed"));
			throw e;
		}
	}
}

int cSelect::readFields(cText *text, cToken *token)
{
	token->nextToken(text);

	if (token->getBufType() == SYMB && token->getBufStr() == "*") {
			token->nextToken(text);
			if (token->getBufStr() == "FROM") {
				return TRUE;
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Wrong instruction, FROM keyword missed"));
				throw e;
			}
	}
	else {
		token->pushBack();
	}

	for (;;) {
		token->nextToken(text);

		if (token->getBufType() == RES) {
			if (token->getBufStr() == "FROM") {
				if (this->fields.empty() == TRUE) {
					dbmsException e;
					e.setMessage(text->exceptionP("Field name missed"));
					throw e;
				}
				else {
					token->pushBack();
					break;
				}
			}
			else {
				this->fields.push_back(token->getBufStr());
			}
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Field name should be without quotation"));
			throw e;
		}
		
		token->nextToken(text);

		if (token->getBufType() == SYMB) {
			if (token->getBufStr() == ",") {
				continue;
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Wrong symbol"));
				throw e;
				return FALSE;
			}
		}
		else if (token->getBufType() == RES && token->getBufStr() == "FROM") {
			return TRUE;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Comma missed"));
			throw e;
			return FALSE;
		}
	}
}

int cSelect::readSelect(cText *text, cToken *token)
{
	readFields(text, token);
	readTables(text, token);

	token->nextToken(text);
	if (token->getBufType() == RES && token->getBufStr() == "WHERE") {
		this->condition = new cSentence();
		if (condition->readSentence(text, token) == TRUE) return TRUE;
		else return FALSE;
	}
	else if (token->getBufType() == END) return TRUE;
	else return FALSE;
}

std::string cSelect::execSelect()
{
	std::vector< std::vector<std::string> > result;
	dbcore dbcore;

	if (this->tables.empty() == FALSE) {
		std::vector<char *> wrTables;
		std::vector<char *> wrFields;

		for (int i = 0; i < this->tables.size(); i++) {
			wrTables.push_back( (char *) this->tables.at(i).data() );
		}
		for (int i = 0; i < this->fields.size(); i++) {
			wrFields.push_back( (char *) this->fields.at(i).data() );
		}
		
		vector < vector <char*> > nullVect;
		result = convertCharVectorToStringVector(dbcore.superJoin(wrTables, nullVect));

		if (this->condition != NULL) {
			result = this->condition->execSentence(result);
		}
		
		if (!this->fields.empty()) {
			result = dbcore.Select(result, wrFields);
		}
		return dbcore.vectorToString(result);
	}
	else {
	}
	return 0;
}


//															INSERT

int cInsert::readTable(cText *text, cToken *token)
{
	token->nextToken(text);

	if (token->getBufType() == RES && token->getBufStr() == "INTO") {

		token->nextToken(text);
		if (token->getBufType() == ID) {
			this->table += token->getBufStr();
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name should be without quotation"));
			throw e;
			return FALSE;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name missed"));
			throw e;
			return FALSE;
		}

		token->nextToken(text);

		if (token->getBufType() == SYMB && token->getBufStr() == "(") {
			if (this->table.empty() == TRUE) return FALSE;
			return TRUE;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Open bracket missed"));
			throw e;
			return FALSE;
		}

	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, INTO keyword missed"));
		throw e;
		return FALSE;
	}
}

int cInsert::readFields(cText *text, cToken *token)
{
	for (;;) {
		token->nextToken(text);
		if (token->getBufType() == ID) {
			this->countFields++;
			this->fields.push_back(token->getBufStr());
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Field name should be without quotation"));
			throw e;
		}
		else if (token->getBufType() == SYMB) {
			if (token->getBufStr() == ",") {
				if (this->fields.empty() == TRUE) return FALSE;
				continue;
			}
			else if (token->getBufStr() == ")") {
				if (this->fields.empty() == TRUE) return FALSE;
				return TRUE;
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Wrong symbol"));
				throw e;
			}
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Field name missed"));
			throw e;
		}
	}
}

int cInsert::readValues(cText *text, cToken *token)
{
	token->nextToken(text);

	if (token->getBufType() == RES && token->getBufStr() == "VALUES") {

		token->nextToken(text);
		if (token->getBufType() == SYMB) {
			if (token->getBufStr() == "(") {

				for (;;) {
					token->nextToken(text);

					if (token->getBufType() == CNST) {
						this->countValues++;
						this->values.push_back(token->getBufStr());
					}
					else if (token->getBufType() == NUM) {
						this->countValues++;
						this->values.push_back( stringify(token->getBufValue()) );
					}
					else if (token->getBufType() == SYMB) {
						if (token->getBufStr() == ",") {
							if (this->fields.empty() == TRUE) return FALSE;
							continue;
						}
						else if (token->getBufStr() == ")") {
							if (this->fields.empty() == TRUE) return FALSE;
							return TRUE;
						}
						else {
							dbmsException e;
							e.setMessage(text->exceptionP("Wrong symbol"));
							throw e;
						}
					}
					else if (token->getBufType() == ID) {
						dbmsException e;
						e.setMessage(text->exceptionP("String data should be inside quotation"));
						throw e;
					}
					else {
						dbmsException e;
						e.setMessage(text->exceptionP("Wrong data"));
						throw e;
					}
				}
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Open bracket missed"));
				throw e;
				return FALSE;
			}
		}
	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, VALUES keyword missed"));
		throw e;
		return FALSE;
	}

}

int cInsert::readInsert(cText *text, cToken *token)
{
	if ( this->readTable(text, token) == FALSE)	return FALSE;
	if ( this->readFields(text, token) == FALSE) return FALSE;
	if ( this->readValues(text, token) == FALSE) return FALSE;

	if (this->countFields != this->countValues) {
		dbmsException e;
		e.setMessage("Fields and values count mismatch");
		throw e;
		return FALSE;
	}
}

std::string cInsert::execInsert()
{
	std::vector<char *> wrCols;
	std::vector< std::vector<char *> > tableColNames;

	datastore2 ds2;

	std::string result = "SUCCESS";

	tableColNames = ds2.getColumns( (char *) this->table.data() );
	for ( int i = 0; i < tableColNames.size(); i++ ) {
		std::string column = tableColNames[i].at(0);

		int pos = stringBelongVector (column, this->fields);
		if ( pos < 0 ) {
			std::string nll = "NULL";
			wrCols.push_back( (char *) nll.data());
		}
		else {
			int sz = this->values.size();
			wrCols.push_back( (char *) this->values.at(pos).data() );
		}
	}

	dbcore dbc;
	dbc.Insert( (char*) this->table.data(), wrCols);

	return result;
}


//															DROP

int cDrop::readDrop(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == RES && token->getBufStr() == "TABLE") {

		token->nextToken(text);

		if (token->getBufType() == ID) {
			this->table += token->getBufStr();
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name should be without quotation"));
			throw e;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name missed"));
			throw e;
		}

		token->nextToken(text);

		if (token->getBufType() != END) {
			dbmsException e;
			e.setMessage(text->exceptionP("Unexpected symbol(s)"));
			throw e;
			return FALSE;
		}
	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, TABLE keyword missed"));
		throw e;
		return FALSE;
	}
}

std::string cDrop::execDrop()
{
	std::string result("SUCCESS");

	try {
		datastore2 ds2;
		ds2.dropTable( (char *) this->table.data() );
	} catch ( dbmsException e ) {
		result = e.getMessage();
	}
	return result;
}


//															CREATE

int cCreate::readCreate(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == RES && token->getBufStr() == "TABLE") {

		token->nextToken(text);

		if (token->getBufType() == ID) {
			this->table += token->getBufStr();
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name should be without quotation"));
			throw e;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name missed"));
			throw e;
			return FALSE;
		}
	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, TABLE keyword missed"));
		throw e;
		return FALSE;
	}

	token->nextToken(text);
	if (token->getBufType() == SYMB && token->getBufStr() == "(") {
		for (;;) {
			token->nextToken(text);
			if (token->getBufType() == ID) {
				this->columns.push_back(token->getBufStr());
			}
			else if (token->getBufType() == CNST) {
				dbmsException e;
				e.setMessage(text->exceptionP("Column name should be without quotation"));
				throw e;
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Column name missed"));
				throw e;
				return FALSE;
			}

			token->nextToken(text);
			if (token->getBufType() == ID) {
				this->types.push_back(token->getBufStr());
			}
			else if (token->getBufType() == CNST) {
				dbmsException e;
				e.setMessage(text->exceptionP("Data type should be without quotation"));
				throw e;
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Data type missed"));
				throw e;
				return FALSE;
			}

			token->nextToken(text);
			if (token->getBufType() == SYMB) {
				if (token->getBufStr() == ",") {
					continue;
				}
				else if (token->getBufStr() == ")") {
					if (this->columns.empty() == TRUE || this->types.empty() == TRUE) return FALSE;
					return TRUE;
				}
				else {
					dbmsException e;
					e.setMessage(text->exceptionP("Wrong symbol(s)"));
					throw e;
					return FALSE;
				}
			}
			else {
				dbmsException e;
				e.setMessage(text->exceptionP("Comma missed"));
				throw e;
				return FALSE;
			}
		}
	}
}

std::string cCreate::execCreate()
{
	std::vector<char *> wrCols;
	std::vector<char *> wrTypes;
	std::string result("SUCCESS");

	for (int i = 0; i < this->columns.size(); i++) {
		wrCols.push_back( (char *) this->columns.at(i).data() );
		wrTypes.push_back( (char *) this->types.at(i).data() );
	}

	datastore2 ds2;
	try{
		ds2.createTable( (char *) this->table.data(), wrCols, wrTypes);
	} catch (dbmsException e) {
		result = e.getMessage();
	}

	return result;
}


//															DELETE

int cDelete::readDelete(cText *text, cToken *token)
{
	token->nextToken(text);

	if (token->getBufType() == RES && token->getBufStr() == "FROM") {

		token->nextToken(text);
		if (token->getBufType() == ID) {
			this->table += token->getBufStr();
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name should be without quotation"));
			throw e;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Table name missed"));
			throw e;
		}

		token->nextToken(text);
		if (token->getBufType() == RES && token->getBufStr() == "WHERE") {
			this->condition = new cCondition();
			if (condition->readCondition(text, token) == TRUE) return TRUE;
			else {
				delete this->condition;
				dbmsException e;
				e.setMessage(text->exceptionP("Condition read error"));
				throw e;
			}
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Wrong instruction, WHERE keyword missed"));
			throw e;
		}

	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, FROM keyword missed"));
		throw e;
	}
}

std::string cDelete::execDelete()
{
	std::vector< std::vector<std::string> > result;
	std::string success("SUCCESS");
	dbcore dbcore;

	if (this->table.empty() == FALSE) {

		std::vector< std::vector<char *> > nullVect;

		result = convertCharVectorToStringVector( dbcore.Select((char *)this->table.data()) );
		
		if (this->condition != NULL) {
			result = this->condition->execCondition(result);

			int pos = findPrimaryKey(result);
			if (pos != -1) {
				dbcore.Delete((char* )this->table.data(), (char *) result.at(pos).at(0).data(), result.at(pos));
			}
		}
		
	}
	else {
	}
	return success;
}


//															UPDATE

int cUpdate::readUpdate(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == ID) {
		this->table += token->getBufStr();
	}
	else if (token->getBufType() == CNST) {
		dbmsException e;
		e.setMessage(text->exceptionP("Table name should be without quotation"));
		throw e;
	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, table name missed"));
		throw e;
	}

	token->nextToken(text);
	if (token->getBufType() == RES && token->getBufStr() == "SET") {
		token->nextToken(text);

		if (token->getBufType() == ID) {
			this->column.push_back(token->getBufStr());
		}
		else if (token->getBufType() == CNST) {
			dbmsException e;
			e.setMessage(text->exceptionP("Column name should be without quotation"));
			throw e;
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Wrong instruction, field name missed"));
			throw e;
		}

		token->nextToken(text);
		if (token->getBufType() == SYMB && token->getBufStr() == "=") {
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Wrong instruction, = symbol missed"));
			throw e;
		}

		token->nextToken(text);
		if (token->getBufType() == CNST) {
			this->column.push_back(token->getBufStr());
		}
		else if (token->getBufType() == NUM) {
			this->column.push_back( stringify(token->getBufValue()) );
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Wrong instruction, update value missed"));
			throw e;
		}

		token->nextToken(text);
		if (token->getBufType() == RES && token->getBufStr() == "WHERE") {
			this->condition = new cCondition();
			if (condition->readCondition(text, token) == TRUE) return TRUE;
			else {
				delete this->condition;
				dbmsException e;
				e.setMessage(text->exceptionP("Condition read error"));
				throw e;
			}
		}
		else {
			dbmsException e;
			e.setMessage(text->exceptionP("Wrong instruction, WHERE keyword missed"));
			throw e;
		}

	}
	else {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong instruction, SET keyword missed"));
		throw e;
	}
}

std::string cUpdate::execUpdate()
{
	std::vector< std::vector<std::string> > result;
	std::string success("SUCCESS");
	dbcore dbcore;

	if (this->table.empty() == FALSE) {

		std::vector< std::vector<char *> > nullVect;

		result = convertCharVectorToStringVector( dbcore.Select((char *)this->table.data()) );
		
		if (this->condition != NULL) {
			result = this->condition->execCondition(result);

			int pos = findPrimaryKey(result);
			if (pos != -1) {
				dbcore.Update((char* )this->table.data(), (char *) result.at(pos).at(0).data(), result.at(pos),
					(char *)this->column.at(0).data(), (char *)this->column.at(1).data());
			}
		}
		
	}
	else {
	}
	return success;
}


//															HELPME

int cHelp::readHelp(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == RES && token->getBufStr() == "CREDITS") {
		dbmsException e;
		e.setMessage("Made in Russia by Kuznetsov Evgeniy & Makarov Nikolay, HCI NSU '08");
		throw e;
	}
	else if (token->getBufType() == NUM && token->getBufValue() == 4815162342) {
		dbmsException e;
		e.setMessage("Ne-ne-ne, David Blaine, net!");
		throw e;
	}
	else if (token->getBufType() == END) {
		dbmsException e;
		e.setMessage("May the Force be with you");
		throw e;
	}
}

std::string cHelp::execHelp()
{
	std::string null;
	return null;
}


//															VARIABLE

int cVariable::setColName(std::string str)
{
	this->colName = str;
	return TRUE;
}

int cVariable::setStr(std::string str)
{
	this->varStr = str;
	return TRUE;
}

int cVariable::setType(int type)
{
	this->varType = type;
	return TRUE;
}

int cVariable::setValue(double val)
{
	this->varValue = val;
	return TRUE;
}

std::string cVariable::getColName()
{
	return this->colName;
}

std::string cVariable::getStr()
{
	return this->varStr;
}

int cVariable::getType()
{
	return this->varType;
}

double cVariable::getValue()
{
	return this->varValue;
}


//															EXPRESSION

int cExpression::readExpr(cText *text, cToken *token)
{
	this->term = new cTerm();

	if(this->term->readTerm(text, token) == TRUE) {
		this->expr_list = new cExpression_list;

		if(this->expr_list->readExpr_list(text, token) == FALSE) {
			delete expr_list;
			expr_list = NULL;
		}
		return TRUE;

	}
	else {
		delete term;
		term = NULL;
		return FALSE;
	}
}

cVariable cExpression::execExpr(std::vector< std::vector<std::string> > data, int line)
{
	cVariable term_l;
	if (this->term != NULL) {
		term_l = this->term->execTerm(data, line);

		if (this->expr_list != NULL) {
			cVariable expr;
			expr = this->expr_list->execExpr_list(data, line);

			if ( calculatable(term_l.getType(), expr.getType()) ) {
				if (this->expr_list->getOper() == '+') {
					term_l.setValue(term_l.getValue() + expr.getValue());
				}
				if (this->expr_list->getOper() == '-') {
					term_l.setValue(term_l.getValue() - expr.getValue());
				}
			}
			else {
				dbmsException e;
				e.setMessage("Operation + or - type mismatch");
				throw e;
			}
		}
	}
	else {
		// Can't be
	}
	return term_l;
}

int cTerm::readTerm(cText *text, cToken *token)
{
	this->factor = new cFactor();
	if (this->factor->readFactor(text, token) == TRUE) {
	
		this->term_list = new cTerm_list();
		if (this->term_list->readTerm_list(text, token) == TRUE){
			return TRUE;
		}
		else {
			delete this->term_list;
			this->term_list = NULL;
			return TRUE;
		}
	}
	else {
		delete this->factor;
		this->factor = NULL;
		return FALSE;
	}
}

cVariable cTerm::execTerm(std::vector< std::vector<std::string> > data, int line)
{
	cVariable fact;
	if (this->factor != NULL) {
		fact = this->factor->execFactor(data, line);

		if (this->term_list != NULL) {
			cVariable term;
			term = this->term_list->execTerm_list(data, line);

			if ( calculatable(term.getType(), fact.getType()) ) {
				if (this->term_list->getOper() == '*') {
					fact.setValue(fact.getValue() * term.getValue());
				}
				if (this->term_list->getOper() == '/') {
					fact.setValue(fact.getValue() / term.getValue());
				}
			}
			else {
				dbmsException e;
				e.setMessage("Operation + or - type mismatch");
				throw e;
			}
		}
	}
	else {
		// Can't be
	}
	return fact;
}

int cFactor::readFactor(cText *text, cToken *token)
{
	token->nextToken(text);
	int currType = token->getBufType();
	if (currType == NUM) {
		this->type = VAR;
		this->var.setValue(token->getBufValue());
		this->var.setType(CTINT);
		return TRUE;
	}
	else if (currType == ID) {
		this->type = VAR;
		this->var.setColName(token->getBufStr());
		this->var.setType(ID);
		return TRUE;
	}
	else if (currType == CNST) {
		this->type = VAR;
		this->var.setStr(token->getBufStr());
		this->var.setType(CTVCHAR);
		return TRUE;
	}
	else if (token->getBufStr() == "(") {
		this->type = EXPR;
		this->expr = new cExpression();
		if (this->expr->readExpr(text, token) == FALSE) {
			delete this->expr;
			this->expr = NULL;
		}
		token->nextToken(text);
		if (token->getBufStr() == ")") {
			return TRUE;
		}
		return FALSE;
		// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   ")" Check necessary
	}
	else return FALSE;
}

cVariable cFactor::execFactor(std::vector< std::vector<std::string> > data, int line)
{
	if (this->type == EXPR) {
		return this->expr->execExpr(data, line);
	}
	else {
		if (this->type == VAR) {
			if (this->var.getType() == CTINT) return this->var;
			if (this->var.getType() == ID) {
				return this->getCell(this->var.getColName(), data, line);
			}
			if (this->var.getType() == CTVCHAR) return this->var;
		}
		else {
			dbmsException e;
			e.setMessage("Wrong factor type");
			throw e;
		}
	}
}

cVariable cFactor::getCell(std::string column, std::vector< std::vector<std::string> > data, int line)
{
	int pos;
	int type;
	cVariable v;
	v.setColName(column);
	pos = findColumn(column, data, &type);
	if (pos != -1) {
		if (CTINT == type) {
			v.setValue( stringToDouble(data.at(pos).at(line) ) );
			v.setType(type);
		}
		else if (CTKEY == type) {
			v.setValue( stringToDouble(data.at(pos).at(line) ) );
			v.setType(type);
		}
		else if (CTVCHAR == type) {
			v.setStr( data.at(pos).at(line) );
			v.setType(type);
		}
		else {
			dbmsException e;
			e.setMessage("Wrong data type");
			throw e;
		}
	}
	else {
		// Column not found
	}
	return v;
}

int cTerm_list::readTerm_list(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == SYMB) {
		if (token->getBufStr() == "*") {
			this->oper = '*';
			this->term = new cTerm();
			if (this->term->readTerm(text, token) == TRUE) {
				return TRUE;
			}
			else {
				delete this->term;
				this->term = NULL;
			}
		}
		else if (token->getBufStr() == "/") {
			this->oper = '/';
			this->term = new cTerm();
			if (this->term->readTerm(text, token) == TRUE) {
				return TRUE;
			}
			else {
				delete this->term;
				this->term = NULL;
			}
		}
		else {
			token->pushBack();
			return FALSE;
		}
	}
	else if (token->getBufType() == ERR) {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong symbol(s)"));
		throw e;
	}
	token->pushBack();
	return FALSE;
}

cVariable cTerm_list::execTerm_list(std::vector< std::vector<std::string> > data, int line)
{
	if (this->term != NULL) {
		return this->term->execTerm(data, line);
	}
	else {
		// This simply can't be, i.e. this->term not exists
	}
}

char cTerm_list::getOper()
{
	return this->oper;
}

int cExpression_list::readExpr_list(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == SYMB) {
		if (token->getBufStr() == "+") {
			this->oper = '+';
			this->expr = new cExpression();
			if (this->expr->readExpr(text, token) == TRUE) {
				return TRUE;
			}
			else {
				delete this->expr;
				this->expr = NULL;
			}
		}
		else if (token->getBufStr() == "-") {
			this->oper = '-';
			this->expr = new cExpression();
			if (this->expr->readExpr(text, token) == TRUE) {
				return TRUE;
			}
			else {
				delete this->expr;
				this->expr = NULL;
			}
		}
		else token->pushBack();
	}
	else if (token->getBufType() == ERR) {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong symbol(s)"));
		throw e;
	}
	token->pushBack();
	return FALSE;
}

cVariable cExpression_list::execExpr_list(std::vector< std::vector<std::string> > data, int line)
{
	if (this->expr != NULL) {
		return this->expr->execExpr(data, line);
	}
	else {
		// Can't be
	}
}

char cExpression_list::getOper()
{
	return this->oper;
}

//															CONDITION

int cCondition::readCondition(cText *text, cToken *token)
{
	this->left = new cExpression();
	this->right = new cExpression();

	this->left->readExpr(text, token);
	
	token->nextToken(text);
	if (token->getBufType() == SYMB) this->operand = token->getBufStr();

	this->right->readExpr(text, token);

	return TRUE;
}

std::vector< std::vector<std::string> > cCondition::execCondition(std::vector< std::vector<std::string> > data)
{
	cVariable left;
	cVariable right;
	std::vector< std::vector<std::string> > result;

	result.push_back( getLine(data, 0) );

	int lastRow = data.at(0).size() - 1;

	for(int i = 1; i < lastRow; i++) {
		left = this->left->execExpr(data, i);
		right = this->right->execExpr(data, i);
		if (calculatable(left.getType(), right.getType()) ) {
			if (this->operand == "<") {
				if (left.getValue() < right.getValue())
					result.push_back( getLine(data, i) );
				continue;
			}
			else if (this->operand == ">") {
				if (left.getValue() > right.getValue())
					result.push_back( getLine(data, i) );
				continue;
			}
			else if (this->operand == "=") {
				if (left.getValue() == right.getValue())
					result.push_back( getLine(data, i) );
				continue;
			}
			else if (this->operand == "<=") {
				if (left.getValue() <= right.getValue())
					result.push_back( getLine(data, i) );
				continue;
			}
			else if (this->operand == ">=") {
				if (left.getValue() >= right.getValue())
					result.push_back( getLine(data, i) );
				continue;
			}
			else if (this->operand == "<>") {
				if (left.getValue() != right.getValue())
					result.push_back( getLine(data, i) );
				continue;
			}
		}
		else if (left.getType() == right.getType() && right.getType() == CTVCHAR) {
			if (this->operand == "=") {
				if (left.getStr() == right.getStr()) 
					result.push_back( getLine(data, i) );
				continue;
			}
			else if (this->operand == "<>") {
				if (left.getStr() != right.getStr())
					result.push_back( getLine(data, i) );
				continue;
			}
		}
		else {
			dbmsException e;
			e.setMessage("Comparison type mismatch");
			throw e;
		}
	}
	result.push_back( getLine(data, lastRow) );
	result = rotateTable(result);
	return result;
}


//															SENTENCE

int cSentence::readSentence(cText *text, cToken *token)
{
	this->conjunction = new cConjunction();

	if(this->conjunction->readConjunction(text, token) == TRUE) {
		this->sentence_list = new cSentence_list;

		if(this->sentence_list->readSentence_list(text, token) == FALSE) {
			delete sentence_list;
			sentence_list = NULL;
		}
		return TRUE;

	}
	else {
		delete conjunction;
		conjunction = NULL;
		return FALSE;
	}
}

std::vector< std::vector<std::string> > cSentence::execSentence(std::vector< std::vector<std::string> > data)
{
	std::vector< std::vector<std::string> > conjunction;
	if (this->conjunction != NULL) {
		conjunction = this->conjunction->execConjunction(data);

		if (this->sentence_list != NULL) {
			std::vector< std::vector<std::string> > sentence;
			sentence = this->sentence_list->execSentence_list(data);
			return vectorUnion(sentence, conjunction);
		}
	}
	else {
		// Can't be
	}
	return conjunction;
}

int cConjunction::readConjunction(cText *text, cToken *token)
{
	this->unit = new cUnit();
	if (this->unit->readUnit(text, token) == TRUE) {
	
		this->conjunction_list = new cConjunction_list();
		if (this->conjunction_list->readConjunction_list(text, token) == FALSE){
			delete this->conjunction_list;
			this->conjunction_list = NULL;
		}
	}
	else {
		delete this->unit;
		this->unit = NULL;
		return FALSE;
	}
	return TRUE;
}

std::vector< std::vector<std::string> > cConjunction::execConjunction(std::vector< std::vector<std::string> > data)
{
	std::vector< std::vector<std::string> > unit;
	if (this->unit != NULL) {
		unit = this->unit->execUnit(data);

		if (this->conjunction_list != NULL) {
			std::vector< std::vector<std::string> > conjunction;
			conjunction = this->conjunction_list->execConjunction_list(unit);
			return conjunction;
		}
	}
	else {
		// Can't be
	}
	return unit;
}

int cUnit::readUnit(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == SYMB && token->getBufStr() == "(") {
		this->sentence = new cSentence();
		this->sentence->readSentence(text, token);
		token->nextToken(text);
		if (token->getBufType() == SYMB && token->getBufStr() == ")") {
			return TRUE;
		}
	}
	else {
		token->pushBack();
		this->condition = new cCondition();
		if (this->condition->readCondition(text, token) == TRUE) return TRUE;
		delete this->condition;
		this->condition = NULL;
	}
	return FALSE;
}

std::vector< std::vector<std::string> > cUnit::execUnit(std::vector< std::vector<std::string> > data)
{
	std::vector< std::vector<std::string> > result;
	if (this->sentence != NULL) {
		result = this->sentence->execSentence(data);
		return result;
	}
	else if (this->condition != NULL) {
		result = this->condition->execCondition(data);
		return result;
	}
	else {
		dbmsException e;
		e.setMessage("Ne-ne-ne, David Blaine, net");
		throw e;
	}
}

int cConjunction_list::readConjunction_list(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == RES) {
		if (token->getBufStr() == "AND") {
			this->conjunction = new cConjunction();
			if (this->conjunction->readConjunction(text, token) == TRUE) {
				return TRUE;
			}
			else {
				delete this->conjunction;
				this->conjunction = NULL;
			}
		}
		else {
			token->pushBack();
			return FALSE;
		}
	}
/*	else if (token->getBufType() == ERR) {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong symbol(s)"));
		throw e;
	}
*/	token->pushBack();
	return FALSE;
}

std::vector< std::vector<std::string> > cConjunction_list::execConjunction_list(std::vector< std::vector<std::string> > data)
{
	if (this->conjunction != NULL) {
		std::vector< std::vector<std::string> > result;
		result = this->conjunction->execConjunction(data);
		return result;
	}
	else {
		// This simply can't be, i.e. this->conjunction not exists
	}
}

int cSentence_list::readSentence_list(cText *text, cToken *token)
{
	token->nextToken(text);
	if (token->getBufType() == RES) {
		if (token->getBufStr() == "OR") {
			this->sentence = new cSentence();
			if (this->sentence->readSentence(text, token) == TRUE) {
				return TRUE;
			}
			else {
				delete this->sentence;
				this->sentence = NULL;
			}
		}
		else {
			token->pushBack();
			return FALSE;
		}
	}
/*	else if (token->getBufType() == ERR) {
		dbmsException e;
		e.setMessage(text->exceptionP("Wrong symbol(s)"));
		throw e;
	}
*/	token->pushBack();
	return FALSE;
}

std::vector< std::vector<std::string> > cSentence_list::execSentence_list(std::vector< std::vector<std::string> > data)
{
	if (this->sentence != NULL) {
		std::vector< std::vector<std::string> > result;
		result = this->sentence->execSentence(data);
		return result;
	}
	else {
		// Can't be
	}
}